//
//  IsoObject.cpp
//  IsoCplus
//
//  Created by 周张林 on 15/9/15.
//
//

#include "IsoObject.h"
#include <cmath>
#include "IsoUtil.h"


USING_NS_CC;


IsoObject* IsoObject::create(unsigned int size,unsigned int spanX ,unsigned int spanZ)
{
    IsoObject *o = new IsoObject();
    if(o&&o->init(size,spanX,spanZ)){
        o->autorelease();
        return o;
    }
    CC_SAFE_DELETE(o);
    return nullptr;
}

bool IsoObject::init(unsigned int size,unsigned int spanX,unsigned int spanZ)
{
    _pos3D = Vec3(0,0,0);
    _size = size;
    _spanX = spanX;
    _spanZ = spanZ;
    _boundingBox = Rect(0,0,0,0);
    _centerOffsetY= size*spanX/2;
    return true;
}

int IsoObject::getSpanX() const
{
    return _spanX;
}
int IsoObject::getSpanZ()const
{
    return _spanZ;
}
int IsoObject::getSize() const
{
    return _size;
}
float IsoObject::getCenterY() const
{
    return  getPositionY()-_centerOffsetY;
}
Rect& IsoObject::boundingBox()
{
    _boundingBox.origin.x = getX();
    _boundingBox.origin.y = getZ();
    if (_isRotate) {
        _boundingBox.size.width = _size * (_spanZ - 1);
        _boundingBox.size.height = _size * (_spanX - 1);
    }else{
        _boundingBox.size.height = _size * (_spanZ - 1);
        _boundingBox.size.width = _size * (_spanX - 1);
    }
    return _boundingBox;
}

void IsoObject::sort(){
    isSort = true;
}

void IsoObject::rotateX(bool value)
{
    _isRotate = value;
    updateSpanPos();
}

void IsoObject::updateScreenPos()
{
    auto pos = IsoUtil::isoToScreen(_pos3D.x,_pos3D.y,_pos3D.z);
    setPosition(pos.x,pos.y);
    updateSpanPos();
}

void IsoObject::updateSpanPos()
{
    _spanPosArray.clear();
    auto t1=0;
    auto t2=0;
    if(_isRotate){
        t1 = _spanZ;
        t2 = _spanX;
    }else{
        t1 = _spanX;
        t2 = _spanZ;
    }
    for(auto i = 0 ;  i<t1 ; i++)
    {
        for(auto j = 0 ; j<t2 ; j++)
        {
            auto pos = Vec3( i*_size+getX(), getY(), j*_size+getZ() );
            _spanPosArray.push_back( pos );
        }
    }
}

const std::vector<Vec3> &IsoObject::getSpanPosArray() const{
    return _spanPosArray;
}


void IsoObject::setX(float value){
    _pos3D.x = value;
    updateScreenPos();
    updateSpanPos();
}

float IsoObject::getX() const
{
    return _pos3D.x;
}


void IsoObject::setY(float value){
    _pos3D.y = value;
    updateScreenPos();
    updateSpanPos();
}

float IsoObject::getY() const
{
    return _pos3D.y;
}

void IsoObject::setZ(float value){
    _pos3D.z = value;
    updateScreenPos();
    updateSpanPos();
}

float IsoObject::getZ() const
{
    return _pos3D.z;
}

void IsoObject::setPos3D(Vec3 &pos)
{
    _pos3D = pos;
    
}

const Vec3& IsoObject::getPos3D() const
{
    return _pos3D;
}

float IsoObject::getDepth(){
    //return (this._pos3D.x + this._pos3D.z) * .866 - this._pos3D.y * .707;
    return -getCenterY();
}

int IsoObject::getNodeX() const
{
    return _nodeX;
}

int IsoObject::getNodeZ() const
{
    return _nodeZ;
}

void IsoObject::setNodePosition(int nodeX,int nodeZ)
{
    _nodeX = nodeZ;
    _nodeZ = nodeZ;
    _pos3D.x = nodeX*_size;
    _pos3D.z = nodeZ*_size;
    updateScreenPos();
    updateSpanPos();

}

void IsoObject::setScreenPos(float x,float y)
{
    setX(x);
    setY(y);
    _pos3D.x = x;
    _pos3D.y = y;
}

void IsoObject::setWalkable(bool value,PathGrid *grid)
{
    updateSpanPos();
    for (auto &v:_spanPosArray) {
        grid->setWalkable( (int)std::floor(v.x/_size) , (int)std::floor(v.z/_size) , value );
    }
}

bool IsoObject::getWalkable( PathGrid *grid)const
{
    bool flag = false;
    for(auto &v:_spanPosArray){
        auto nodeX = (int)std::floor(v.x/_size);
        auto nodeY = (int)std::floor(v.z/_size);
        if(nodeX<0 || nodeX>grid->getGridX()-1) return false;
        if(nodeY<0 || nodeY>grid->getGridZ()-1) return false;
        flag = grid->getNode(nodeX,nodeY)->walkable;
        if(!flag) return false;
    }
    return true;
}

bool IsoObject::getRotatable(PathGrid *grid)
{
    if (_spanX==_spanZ ) return true;
    
    setWalkable(true,grid);
    _isRotate = ! _isRotate;
    updateSpanPos();
    bool flag = getWalkable(grid);
    //还原
    _isRotate = !_isRotate;
    setWalkable(false,grid);
    return flag;
}

IsoObject::~IsoObject(){
    _spanPosArray.clear();
}